# -*- coding: utf-8 -*-

 ###############################################
 ##                                             ##
 ##   Módulo modelo                              ##
 ##                                              ##
 ##                                              ##
 ##   de la línea Básicos                        ##
 ##   de Críptidos Digitales                     ##
 ##   GPL (c)2008                                ##
  ##                                             ##
    ###############################################

# print (0), "man                 begin"

import sys, os
from decimal import Decimal as dec
import datetime
import sqlalchemy

from sqlalchemy import sql, orm
# import sqlalchemy.orm as orm

from sqlalchemy.orm import mapper, relation, backref
from sqlalchemy.ext.declarative import declarative_base

import configuracion

import sqlite as backend


config = configuracion.Parser()

logLevel = config.pull('properties', 'loggingLevel')


# print (0), "man                   definitions"


class Atributo(object):
    """
        Contiene atributos de otras clases, pueden ser del sistema o de otros
        registros de otras tablas
    """
    def __init__(self, *args, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return ("<Atributo(id:%s, grupo:'%s', nombre:'%s', valor:'%s', referencia:'%s')>" % (self.id, self.grupo, self.nombre, self.valor, self.referencia)).encode('utf8')

    def setData(self, useDefaults=False, **kwds):
        if 'id' in kwds.keys():         self.id = kwds.pop('id')
        if 'code' in kwds.keys():       self.code = kwds.pop('code')
        if 'grupo' in kwds.keys():      self.grupo = kwds.pop('grupo')
        if 'nombre' in kwds.keys():     self.nombre = kwds.pop('nombre')
        if 'valor' in kwds.keys():      self.valor = kwds.pop('valor')
        if 'referencia' in kwds.keys(): self.referencia = kwds.pop('referencia')


class AtributoProducto(object):

    def __init__(self, *args, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return ("<AtributoProducto(id:%s, producto_id:%s, nombre:'%s', valor:'%s', factor1:'%s', factor2:'%s', referencia:'%s', atributo_id:'%s', usuario:'%s', status:'%s', fechaalta:'%s', fechabaja:'%s')>" % (self.id, self.producto_id, self.nombre, self.valor, self.factor1, self.factor2, self.referencia, self.atributo_id, self.usuario, self.status, self.fechaalta, self.fechabaja)).encode('utf8')

    def setData(self, useDefaults=False, **kwds):
        if 'id' in kwds.keys():         self.id = kwds.pop('id')
        if 'producto_id' in kwds.keys(): self.producto_id = kwds.pop('producto_id')
        if 'nombre' in kwds.keys():     self.nombre = kwds.pop('nombre')
        if 'valor' in kwds.keys():      self.valor = kwds.pop('valor')
        if 'factor1' in kwds.keys():    self.factor1 = kwds.pop('factor1')
        if 'factor2' in kwds.keys():    self.factor2 = kwds.pop('factor2')
        if 'referencia' in kwds.keys(): self.referencia = kwds.pop('referencia')
        if 'atributo_id' in kwds.keys(): self.atributo_id = kwds.pop('atributo_id')
        if 'status' in kwds.keys():     self.status = kwds.pop('status')
        if 'fechaalta' in kwds.keys():  self.fechaalta = kwds.pop('fechaalta')
        else:                           self.fechaalta = datetime.datetime.today()
        if 'fechabaja' in kwds.keys():  self.fechabaja = kwds.pop('fechabaja')
        if 'usuario' in kwds.keys():    self.usuario = kwds.pop('usuario')


class AtributoRol(object):

    def __init__(self, *args, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return ("{AtributoRol(id:%s, rol_id:%s, nombre:'%s', valor:'%s', referencia:%s, usuario:%s)}" % (self.id, self.rol_id, self.nombre, self.valor, self.referencia, self.usuario)).encode('utf8')

    def setData(self, useDefaults=False, **kwds):
        if 'id' in kwds.keys():         self.id = kwds['id']
        if 'rol_id' in kwds.keys():     self.rol_id = kwds['rol_id']
        if 'nombre' in kwds.keys():     self.nombre = kwds['nombre']
        if 'valor' in kwds.keys():      self.valor = kwds['valor']
        if 'referencia' in kwds.keys(): self.referencia = kwds['referencia']
        if 'usuario' in kwds.keys():    self.usuario = kwds['usuario']


class Acepcion(object):
    def __init__(self, *args, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return ("<Acepcion (id:%s, producto_id:%s, rol_id:%s, codigo:'%s', nombre:'%s', costo:%s, descuentoindividual:%s, descuentogeneral:%s, referencia:%s, status:'%s', fechaalta:%s, fechabaja:%s)>" % (self.id, self.producto_id, self.rol_id, self.codigo, self.nombre, self.costo, self.descuentoindividual, self.descuentogeneral, self.referencia, self.status, self.fechaalta, self.fechabaja)).encode('utf8')

    def setData(self, useDefaults=False, **kwds):
        if 'id' in kwds.keys():         self.id = kwds['id']
        if 'producto_id' in kwds.keys(): self.producto_id = kwds.pop('producto_id')
        if 'rol_id' in kwds.keys():     self.rol_id = kwds.pop('rol_id')
        if 'codigo' in kwds.keys():     self.codigo = unicode(kwds.pop('codigo'))
        if 'nombre' in kwds.keys():     self.nombre = kwds.pop('nombre')
        if 'costo' in kwds.keys():      self.costo = kwds.pop('costo')
        if 'descuentoindividual' in kwds.keys(): self.descuentoindividual = kwds.pop('descuentoindividual')
        else:   self.descuentoindividual = '0'
        if 'descuentogeneral' in kwds.keys(): self.descuentogeneral = kwds.pop('descuentogeneral')
        if 'referencia' in kwds.keys(): self.referencia = kwds.pop('referencia')
        if 'status' in kwds.keys():     self.status = kwds.pop('status')
        if 'fechaalta' in kwds.keys():  self.fechaalta = kwds.pop('fechaalta')
        else:                           self.fechaalta = datetime.datetime.today()
        if 'fechabaja' in kwds.keys():  self.fechabaja = kwds.pop('fechabaja')
        # if kwds.has_key('master_id'):   self.master_id = kwds.pop('master_id')


class Entidad(object):
    """
        Define características únicas e inmutables de cada entidad
    """
    def __init__(self, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return ("<Entidad(id:%s, personalidad:%s, nombre:'%s', nombre2:'%s', alias:'%s', fechanacimiento:'%s', rfc:'%s, curp:'%s')>" % (self.id, self.personalidad, self.nombre, self.nombre2, self.alias, self.fechanacimiento, self.rfc, self.curp)).encode('utf8')

    def setData(self, useDefaults=False, **kwds):
        if 'id' in kwds.keys():         self.id = kwds.pop('id')
        if 'personalidad' in kwds.keys(): self.personalidad = kwds.pop('personalidad')
        if 'nombre' in kwds.keys():     self.nombre = kwds.pop('nombre')
        if 'nombre2' in kwds.keys():    self.nombre2 = kwds.pop('nombre2')
        if 'alias' in kwds.keys():      self.alias = kwds.pop('alias')
        else:   self.alias = u""
        if 'fechanacimiento' in kwds.keys(): self.fechanacimiento = kwds.pop('fechanacimiento')
        else:   self.fechanacimiento = datetime.date(1900,1,1)
        if 'rfc' in kwds.keys():        self.rfc = kwds.pop('rfc')
        if 'curp' in kwds.keys():       self.curp = kwds.pop('curp')
        else:   self.curp = u""



class Equipo(object):

    def __init__(self, *args, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return "<Equipo(id:%s, propietario_id:%s, codigo:'%s', tipo_id:'%s', marca_id:'%s', linea_id:'%s', modelo_id:'%s', serie:%s, registro:'%s', color:'%s', observaciones:'%s')>" % (self.id, self.propietario_id, self.codigo, self.tipo_id, self.marca_id, self.linea_id, self.modelo_id, self.serie, self.registro, self.color, self.observaciones)

    def setData(self, useDefaults=False, **kwds):
        if 'id' in kwds.keys():         self.id = kwds.pop('id')
        if 'propietario_id' in kwds.keys(): self.propietario_id = kwds.pop('propietario_id')
        if 'codigo' in kwds.keys():     self.codigo = kwds.pop('codigo')
        if 'tipo_id' in kwds.keys():    self.tipo_id = kwds.pop('tipo_id')
        if 'marca_id' in kwds.keys():   self.marca_id = kwds.pop('marca_id')
        if 'linea_id' in kwds.keys():   self.linea_id = kwds.pop('linea_id')
        if 'modelo_id' in kwds.keys():  self.modelo_id = kwds.pop('modelo_id')
        if 'serie' in kwds.keys():      self.serie = kwds.pop('serie')
        if 'registro' in kwds.keys():   self.registro = kwds.pop('registro')
        if 'color' in kwds.keys():      self.color = kwds.pop('color')
        if 'observaciones' in kwds.keys(): self.observaciones = kwds.pop('observaciones')


class Operacion(object):
    """
        tipo    [u'solicitud']
        cuentas [u'caja', u'inventarios', u'pagos', u'cobros']
        status  [u'abierta', u'cerrada', u'cancelada']
    """

    procesos = relation('Proceso', secondary=backend.proceso_operacion, backref='procesos')

    def __init__(self, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return ("<Operacion (id:%s, tipo:'%s', cuenta:'%s', fecha:%s, fecha2:%s, monto:%s, status:'%s', referencia:'%s', comentarios:'%s') >" % (self.id, self.tipo, self.cuenta, self.fecha, self.fecha2, self.monto, self.status, self.referencia, self.comentarios)).encode('utf8')

    def setData(self, useDefaults=False, **kwds):
        if 'id' in kwds.keys():         self.id = kwds.pop('id')
        if 'tipo' in kwds.keys():       self.tipo = kwds.pop('tipo')
        if 'cuenta' in kwds.keys():     self.cuenta = kwds.pop('cuenta')
        if 'fecha' in kwds.keys():      self.fecha = kwds.pop('fecha')
        else:                           self.fecha = datetime.datetime.today()
        if 'fecha2' in kwds.keys():     self.fecha2 = kwds.pop('fecha2')
        if 'monto' in kwds.keys():      self.monto = kwds.pop('monto')
        if 'status' in kwds.keys():     self.status = kwds.pop('status')
        if 'referencia' in kwds.keys(): self.referencia = kwds.pop('referencia')
        else: self.referencia = u""
        if 'comentarios' in kwds.keys(): self.comentarios = kwds.pop('comentarios')
        else: self.comentarios = u""


class Rol(object):
    """
        Define funciones de las entidades, y datos relacionados con esas
        funciones
    """
    def __init__(self, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return ("<Rol(id:%s, entidad_id:%s, tipo_id:'%s', funcion:'%s', comentarios:'%s')>" % (self.id, self.entidad_id, self.tipo_id, self.funcion, self.comentarios)).encode('utf-8')

    def setData(self, useDefaults=False, **kwds):
        if 'id' in kwds.keys():         self.id = kwds.pop('id')
        if 'code' in kwds.keys():       self.code = kwds.pop('code')
        if 'entidad_id' in kwds.keys(): self.entidad_id = kwds.pop('entidad_id')
        if 'tipo_id' in kwds.keys():    self.tipo_id = kwds.pop('tipo_id')
        if 'funcion' in kwds.keys():    self.funcion = kwds.pop('funcion')
        if 'comentarios' in kwds.keys(): self.comentarios = kwds.pop('comentarios')
        if 'dato1' in kwds.keys():      self.dato1 = kwds.pop('dato1')
        if 'dato2' in kwds.keys():      self.dato2 = kwds.pop('dato2')


class Direccion(object):
    def __init__(self, **kwds):
        if 'rol_id' in kwds.keys():     self.rol_id = kwds['rol_id']
        if 'tipo' in kwds.keys():       self.tipo = kwds['tipo']
        else:   self.tipo = u"personal"
        if 'lugar_id' in kwds.keys():   self.lugar_id = kwds['lugar_id']
        if 'areanominal' in kwds.keys(): self.areanominal = kwds['areanominal']
        if 'areapostal' in kwds.keys(): self.areapostal = kwds['areapostal']
        if 'areatelefonica' in kwds.keys(): self.areatelefonia = kwds['areatelefonia']
        else:   self.areatelefonica = u""
        if 'calle' in kwds.keys():      self.calle = kwds['calle']

    def __repr__(self):
        return ("<Direccion(id:%s, rol_id:%s, tipo:%s, lugar_id:%s, areanominal:'%s', areapostal:'%s', areatelefonia:'%s', calle:'%s')>" % (self.id, self.rol_id, self.tipo, self.lugar_id, self.areanominal, self.areapostal, self.areatelefonia, self.calle)).encode('utf8')


class Servicio(object):
    def __init__(self, **kwds):
        if 'documento_id' in kwds.keys():   self.documento_id = kwds['documento_id']
        if 'equipo_id' in kwds.keys():      self.equipo_id = kwds['equipo_id']
        if 'nivel1' in kwds.keys():         self.nivel1 = kwds['nivel1']
        if 'nivel2' in kwds.keys():         self.nivel2 = kwds['nivel2']
        if 'accesorios' in kwds.keys():     self.accesorios = kwds['accesorios']
        if 'observaciones' in kwds.keys():  self.observaciones = kwds['observaciones']
        else:   self.observaciones = u""
        if 'sintomas' in kwds.keys():       self.sintomas = kwds['sintomas']
        if 'fechadiagnostico' in kwds.keys(): self.fechadiagnostico = kwds['fechadiagnostico']
        if 'tecnico_id' in kwds.keys():     self.tecnico_id = kwds['tecnico_id']
        if 'diagnostico' in kwds.keys():    self.diagnostico = kwds['diagnostico']

    def __repr__(self):
        return "<Servicio(documento_id:%s, equipo_id:%s, nivel1:%s, nivel2:%s, accesorios:%s, observaciones:%s, sintomas:%s, fechadiagnostico:%s, tecnico_id:%s, diagnostico:%s)>" % (self.documento_id, self.equipo_id, self.nivel1, self.nivel2, self.accesorios, self.observaciones, self.sintomas, self.fechadiagnostico, self.tecnico_id, self.diagnostico)


class Producto(object):
    """
        Contiene los datos actuales de un producto, todos los atributos son
        mutables, excepto el id de la base de datos.
    """
    def __init__(self, *args, **kwds):
        if kwds.has_key('id'):              self.id = kwds.pop('id')
        if kwds.has_key('tipo_id'):         self.tipo_id = kwds.pop('tipo_id')
        if kwds.has_key('clasificacion_id'):self.clasificacion_id = kwds.pop('clasificacion_id')
        if kwds.has_key('unidad_id'):       self.unidad_id = kwds.pop('unidad_id')
        if kwds.has_key('minimo'):          self.minimo = kwds.pop('minimo')
        if kwds.has_key('maximo'):          self.maximo = kwds.pop('maximo')
        if kwds.has_key('actual'):          self.actual = kwds.pop('actual')
        if kwds.has_key('costopromedio'):   self.costopromedio = kwds.pop('costopromedio')
        if kwds.has_key('margen'):          self.margen = kwds.pop('margen')
        if kwds.has_key('impuesto'):        self.impuesto = kwds.pop('impuesto')
        if kwds.has_key('precio'):          self.precio = kwds.pop('precio')
        if 'fechaalta' in kwds.keys():      self.fechaalta = kwds.pop('fechaalta')
        else:                               self.fechaalta = datetime.datetime.today()
        if 'fechabaja' in kwds.keys():      self.fechabaja = kwds.pop('fechabaja')
        if 'status' in kwds.keys():         self.status = kwds.pop('status')

        if kwds:
            print "Sobran atributos al crear instancia de Producto:\n%s" % kwds
            return kwds

    def __repr__(self):
        return (u"<Producto(id:%s, tipo_id:%s, clasificacion_id:%s, unidad_id:%s, costopromedio:%s, impuesto:%s, margen:%s, precio:%s, mínimo:%s, máximo:%s, actual:%s, fechaalta:%s, fechabaja:%s, status:'%s')>" % (self.id, self.tipo_id, self.clasificacion_id, self.unidad_id, self.costopromedio, self.impuesto, self.margen, self.precio, self.minimo, self.maximo, self.actual, self.fechaalta, self.fechabaja, self.status)).encode('utf-8')


class ArchivoProducto(object):
    """
        Contiene los cambios que han sufrido los datos mutables de los productos
    """
    def __init__(self, producto, atributo, valor, fecha):
        if kwds.has_key('producto_id'): self.producto_id = kwds['producto']
        if kwds.has_key('atributo'):    self.atributo = kwds['atributo']
        if kwds.has_key('valor'):       self.valor = kwds['valor']
        if kwds.has_key('fecha'):       self.fecha = kwds['fecha']

    def __repr__(self):
        return "<ArchivoProducto('%s', '%s', '%s', '%s')>" % (self.producto_id, self.atributo, self.valor, self.fecha)


class Proceso(object):
    """
        status  [u'abierto', u'cerrado', 'cancelado']
    """
    def __init__(self, **kwds):
        if 'tipo' in kwds.keys():   self.tipo = kwds['tipo']
        if 'fecha' in kwds.keys():  self.fecha = kwds['fecha']
        else:                       self.fecha = datetime.datetime.today()
        if 'status' in kwds.keys(): self.status = kwds['status']

    def __repr__(self):
        return "<Proceso(id:%s, tipo:'%s', fecha:'%s', status:'%s')>" % (self.id, self.tipo, self.fecha, self.status)


class Documento(object):
    """
        status  [u'abierto', u'cerrado', u'cancelado']
    """
    def __init__(self, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return (u"<Documento(id:%s, operacion_id:%s, tipo_id:%s, folio:'%s', fecha:'%s', rol_id:%s, subtotal:%s, descuento:%s, descuentoporcentaje:%s, impuesto:%s, impuestoporcentaje:%s, total:%s, status:'%s', referencia:'%s', fechaalta:'%s')>" % (self.id, self.operacion_id, self.tipo_id, self.folio, self.fecha, self.rol_id, self.subtotal, self.descuento, self.descuentoporcentaje, self.impuesto, self.impuestoporcentaje, self.total, self.status, self.referencia, self.fechaalta)).encode('utf8')

    def setComplemento(self, complemento):
        self.complemento = complemento

    def setData(self, useDefaults=False, **kwds):
        if 'operacion_id' in kwds.keys(): self.operacion_id = kwds.pop('operacion_id')
        if 'tipo_id' in kwds.keys():    self.tipo_id = kwds.pop('tipo_id')
        if 'folio' in kwds.keys():      self.folio = kwds.pop('folio')
        if 'fecha' in kwds.keys():      self.fecha = kwds.pop('fecha')
        if 'rol_id' in kwds.keys():     self.rol_id = kwds.pop('rol_id')
        if 'subtotal' in kwds.keys():   self.subtotal = kwds.pop('subtotal')
        if 'descuento' in kwds.keys():  self.descuento = kwds.pop('descuento')
        if 'descuentoporcentaje' in kwds.keys(): self.descuentoporcentaje = kwds.pop('descuentoporcentaje')
        else:                           self.descuentoporcentaje = dec("0")
        if 'impuesto' in kwds.keys():   self.impuesto = kwds.pop('impuesto')
        if 'impuestoporcentaje' in kwds.keys(): self.impuestoporcentaje = kwds.pop('impuestoporcentaje')
        else:                           self.impuestoporcentaje = dec("0")
        if 'total' in kwds.keys():      self.total = kwds.pop('total')
        if 'status' in kwds.keys():     self.status = kwds.pop('status')
        else:                           self.status = u'abierto'
        if 'referencia' in kwds.keys(): self.referencia = kwds.pop('referencia')
        if 'fechaalta' in kwds.keys():  self.fechaalta = kwds.pop('fechaalta')
        else:                           self.fechaalta = datetime.datetime.today()
        if 'useDefaults' in kwds:       kwds.pop('useDefaults')

        if kwds:
            print "Sobran parametros en Documento.setData()", kwds


class PartidaDocumento(object):
    """
        status [u'abierta', u'cerrada', u'cancelada']
    """
    def __init__(self, *args, **kwds):
        self.setData(useDefaults=True, **kwds)

    def __repr__(self):
        return "<PartidaDocumento(id:%s, documento_id:%s, producto_id:%s, cantidad:%s, costo:%s, precio:%s, descuento:%s, impuesto:%s, precioneto:%s, status:'%s')>" % (self.id, self.documento_id, self.producto_id, self.cantidad, self.costo, self.precio, self.descuento, self.impuesto, self.precioneto, self.status)

    def setData(self, useDefaults=False, **kwds):
        if 'documento_id' in kwds.keys(): self.documento_id = kwds.pop('documento_id')
        if 'producto_id' in kwds.keys(): self.producto_id = kwds.pop('producto_id')
        if 'cantidad' in kwds.keys():   self.cantidad = kwds.pop('cantidad')
        if 'costo' in kwds.keys():      self.costo = kwds.pop('costo')
        if 'precio' in kwds.keys():     self.precio = kwds.pop('precio')
        if 'descuento' in kwds.keys():  self.descuento = kwds.pop('descuento')
        if 'impuesto' in kwds.keys():   self.impuesto = kwds.pop('impuesto')
        if 'precioneto' in kwds.keys(): self.precioneto = kwds.pop('precioneto')
        if 'status' in kwds.keys():     self.status = kwds.pop('status')

        if kwds:
            print "Not all arguments parsed during PartidaDocumento instance creation: %s" % kwds



mapper(Atributo, backend.atributos)

mapper(Entidad, backend.entidades, properties={'roles':relation(Rol, backref='Entidad', cascade="all, delete, delete-orphan")})

mapper(Rol, backend.roles, properties={'entidad':relation(Entidad), 'direcciones':relation(Direccion, backref='rol', cascade="all, delete, delete-orphan"), 'atributos':relation(AtributoRol, backref='rol')})

mapper(AtributoRol, backend.atributosrol)

mapper(Direccion, backend.direcciones, properties={'lugar': relation(Atributo)})

# mapper(Contacto, backend.contactos)

mapper(Operacion, backend.operaciones, properties={
'documentos': relation(Documento, primaryjoin=backend.documentos.c.operacion_id==backend.operaciones.c.id, foreign_keys=[backend.documentos.c.operacion_id], backref='operacion')})
# 'procesos':relation(Proceso, secondary=backend.proceso_operacion, primaryjoin=backend.operaciones.c.id==backend.proceso_operacion.c.operacion_id, secondaryjoin=backend.proceso_operacion.c.proceso_id==backend.procesos.c.id)

mapper(Producto, backend.productos, properties={
'clasificacion':relation(Atributo, primaryjoin=backend.productos.c.clasificacion_id==backend.atributos.c.id),

'tipo':relation(Atributo, primaryjoin=backend.productos.c.tipo_id==backend.atributos.c.id),

'atributos':relation(AtributoProducto, primaryjoin=sqlalchemy.sql.and_(backend.productos.c.id==backend.atributosproducto.c.producto_id, backend.atributosproducto.c.status==u'actual')),

'acepciones':relation(Acepcion, primaryjoin=sqlalchemy.sql.and_(backend.productos.c.id==backend.acepciones.c.producto_id, backend.acepciones.c.status==u'actual')),

'lineas':relation(Atributo, secondary=backend.atributosproducto,
primaryjoin=sqlalchemy.sql.and_(backend.productos.c.id==backend.atributosproducto.c.producto_id, backend.atributosproducto.c.nombre==u'línea', backend.atributosproducto.c.status==u'actual'),
secondaryjoin=backend.atributosproducto.c.atributo_id==backend.atributos.c.id),

'precios':relation(AtributoProducto, primaryjoin=sqlalchemy.sql.and_(backend.productos.c.id==backend.atributosproducto.c.producto_id, backend.atributosproducto.c.nombre==u'precio', backend.atributosproducto.c.status==u'actual'))

})

mapper(AtributoProducto, backend.atributosproducto, properties={
'producto':relation(Producto, backref='AtributoProducto'),
'atributo':relation(Atributo, primaryjoin=backend.atributosproducto.c.atributo_id==backend.atributos.c.id)})

mapper(Acepcion, backend.acepciones, properties={'producto':relation(Producto), 'rol':relation(Rol)})

mapper(Equipo, backend.equipos, properties={'propietario':relation(Rol),
'marca':relation(Atributo, primaryjoin=backend.equipos.c.marca_id==backend.atributos.c.id, foreign_keys=[backend.equipos.c.marca_id]),
'linea':relation(Atributo, primaryjoin=backend.equipos.c.linea_id==backend.atributos.c.id, foreign_keys=[backend.equipos.c.linea_id]),
'modelo':relation(Atributo, primaryjoin=backend.equipos.c.modelo_id==backend.atributos.c.id, foreign_keys=[backend.equipos.c.modelo_id])})

mapper(ArchivoProducto, backend.archivosproducto, properties={'producto':relation(Producto)})

mapper(Proceso, backend.procesos, properties={'operaciones': relation(Operacion, secondary=backend.proceso_operacion, backref='procesos')})

mapper(Documento, backend.documentos, properties={'tipo':relation(Atributo), 'partidas':relation(PartidaDocumento, backref='documento', cascade="all, delete, delete-orphan"), 'rol':relation(Rol)})

mapper(PartidaDocumento, backend.partidasdocumento, properties={'producto':relation(Producto, backref='PartidaDocumento')})

mapper(Servicio, backend.servicios, properties={'documento':relation(Documento, backref=backref('servicio', uselist=False)), 'equipo':relation(Equipo, backref='Equipo'), 'tecnico':relation(Rol)})


def acepcionI(**datos):
    #! No se ha implementado el caso de que se reciba una instancia como parámetro
    """ Primero se prueba con todos los parámetros
        por si se trata de una consulta, también funciona si se recibe sólo el id """
    if 'status' not in datos.keys():
        datos['status'] = u'actual'


    acepcion = session().query(Acepcion).filter_by(**datos).first()

    if not acepcion:
        print 333, datos
        """ Si no es consulta, es modificación o alta """
        if 'id' in datos.keys():
            """ Si se recibe el id y no se trata de una consulta (algún parámetro no coincide con el contenido en la base de datos), se trata de una modificación"""
            acepcion = session().query(Acepcion).filter(Acepcion.id==datos.pop('id')).first()
        if not acepcion:
            """ Se insiste si se trata de modificación, búsqueda por unique constraint"""
            acepcion = session().query(Acepcion).filter(Acepcion.rol_id==datos['rol_id']).filter(Acepcion.producto_id==datos['producto_id']).filter(Acepcion.status==datos['status']).first()
        if not acepcion:
            """ Si no es modificación, es alta """
            acepcion = Acepcion(**datos)
            session().add(acepcion)
        else:
            """ Es modificación, crear la acepcion de respaldo """
            acepcionOld = Acepcion(producto_id=acepcion.producto_id, rol_id=acepcion.rol_id, codigo=acepcion.codigo, nombre=acepcion.nombre, costo=acepcion.costo, descuentoindividual=acepcion.descuentoindividual, descuentogeneral=acepcion.descuentogeneral, referencia=acepcion.referencia, status=u'obsoleta', fechaalta=acepcion.fechaalta, fechabaja=datetime.datetime.today())
            session().add(acepcionOld)

        acepcion.setData(**datos)

        session().commit()

    return acepcion


def acepcionExists(**filtros):
    acepcion = session().query(Acepcion).filter_by(**filtros).first()
    if acepcion:
        return True
    else:
        return False


# def acepcionesI(**filtros):
    # m = "man.acepcionesI()", filtros

    # if 'status' not in filtros.keys():
        # filtros['status'] = u'actual'

    # if 'clasificacion' in filtros.keys():
        # clasificacion = filtros.pop('clasificacion')
        # if 'nombre' in filtros.keys():
            # registros = man.session().query(Acepcion).filter(Acepcion.rol_id==filtros['rol_id']).filter(func.lower(Acepcion.nombre).like("%s%%" % filtros['nombre'])).filter(Acepcion.status==filtros['status']).filter(producto.clasificacion==clasificacion).order_by(Acepcion.nombre).all()
        # elif 'codigo' in filtros.keys():
            # registros = man.session().query(Acepcion).filter(Acepcion.rol_id==filtros['rol_id']).filter(func.lower(Acepcion.codigo).like("%s%%" % filtros['codigo'])).filter(Acepcion.status==filtros['status']).join(Producto).filter(Producto.clasificacion==clasificacion).order_by(Acepcion.nombre).all()
    # else:
        # if 'nombre' in filtros.keys():
            # registros = man.session().query(Acepcion).filter(Acepcion.rol_id==filtros['rol_id']).filter(func.lower(Acepcion.nombre).like("%s%%" % filtros['nombre'])).filter(Acepcion.status==filtros['status']).order_by(Acepcion.nombre).all()
        # elif 'codigo' in filtros.keys():
            # registros = man.session().query(Acepcion).filter(Acepcion.rol_id==filtros['rol_id']).filter(func.lower(Acepcion.codigo).like("%s%%" % filtros['codigo'])).filter(Acepcion.status==filtros['status']).order_by(Acepcion.nombre).all()
        # else:
            # registros = man.session().query(Acepcion).filter(Acepcion.rol_id==filtros['rol_id']).filter(Acepcion.status==u'actual').order_by(Acepcion.codigo).all()
    # return registros


def atributoI(**datos):
    #! No se ha implementado el caso de que se reciba una instancia como parámetro
    """ Primero se prueba con todos los parámetros
        por si se trata de una consulta, también funciona si se recibe sólo el id """
    atributo = session().query(Atributo).filter_by(**datos).first()
    if not atributo:
        """ Si no es consulta, es modificación o alta """
        """ Si se recibe el id y no se trata de una consulta (algún parámetro no coincide con el contenido en la base de datos), se trata de una modificación"""
        if 'id' in datos.keys():
            atributo = session().query(Atributo).filter(Atributo.id==datos.pop('id')).first()

        if not atributo:
            """Se insiste si se trata de modificación, búsqueda por unique constraint"""
            atributo = session().query(Atributo).filter(Atributo.grupo==datos['grupo']).filter(Atributo.nombre==datos['nombre']).first()

        if not atributo:
            """ Si no es modificación, es alta """
            atributo = Atributo(**datos)
        else:
            atributo.setData(**datos)

        session().add(atributo)
        session().commit()

    return atributo


def atributosI(**datos):
    if 'order' in datos.keys():
        order = datos.pop('order')
        registros = session().query(Atributo).filter_by(**datos).order_by(order).all()
    else:
        registros = session().query(Atributo).filter_by(**datos).all()
    return registros


def atributoRolI(**datos):
    #! No se ha implementado el caso de que se reciba una instancia como parámetro
    try:
        """ Primero se prueba con todos los parámetros
            por si se trata de una consulta, también funciona si se recibe sólo el id """
        atributo = session().query(AtributoRol).filter_by(**datos).one()
    except:
        """ Si no es consulta, es modificación o alta """
        try:
            """ Si se recibe el id y no se trata de una consulta (algún parámetro no
                coincide con el contenido en la base de datos),
                se trata de una modificación"""
            atributo = session().query(AtributoRol).filter(AtributoRol.id==datos['id']).one()
            atributo.setData(**datos)
        except:
            try:
                """Se insiste si se trata de modificación, búsqueda por unique constraint"""
                atributo = session().query(AtributoRol).filter(AtributoRol.rol_id==datos['rol_id']).filter(AtributoRol.nombre==datos['nombre']).filter(AtributoRol.valor==datos['valor']).one()
                atributo.setData(**datos)
            except:
                """ Si no es modificación, es alta """
                atributo = AtributoRol(**datos)
        session().add(atributo)
        session().commit()

    return atributo


def agregaEntidad(datos):           # print "man.agregarEntidad()"
    f=g
    #! in use = False
    #! Needs refactoring (is this method necesary?)


def dameCuentas():
    f=g
    #! Necesita refactorizacion

    registro = session().query(Rol).filter(Rol.tipo==u'propio').one()
    if registro.dato2:
        cuentas = registro.dato2.split('; ')
    else:
        cuentas = []
    return cuentas

def dameDocumento(**filtros):
    registro = session().query(Documento).filter_by(**filtros).first()
    return registro

def dameDocumentos(**filtros):      # print "man.dameDocumentos()"
    registros = session().query(Documento).filter_by(**filtros).all()
    return registros

def dameEntidad(**filtros):
    registro = session().query(Entidad).filter(Entidad.id==filtros['id']).one()
    return registro

def impuestoGeneral():
    valor = dec(atributoI(grupo=u'sistema', nombre=u'impuestoGeneral').valor)
    return valor


def lugar(**filtros):
    filtros['grupo'] = u'lugar'
    registro = atributoI(**filtros)
    return registro


def lugares():
    registros = atributosI(grupo=u'lugar')
    return registros


def dameOperaciones(**filtros):
    registros = session().query(Operacion).filter_by(**filtros).all()
    return registros


def damePersonalidad(**filtros):
    f=g
    #! Obsoleto, use personalidad()

    filtros['propietario'] = u'entidades'
    filtros['nombre'] = u'personalidad'
    registro = session().query(Atributo).filter_by(**filtros).one()
    return registro


def personalidad(**filtros):
    registro = atributoI(grupo=u'personalidadEntidad', **filtros)
    return registro


def productoI(**filtros):
    registro = session().query(Producto).filter(Producto.id==filtros['id']).one()
    return registro


def dameRecuperacion(modo=None):
    try:
        if not modo:
            pregunta = atributoI(grupo=u'sistema', nombre=u'pregunta').valor
            respuesta = atributoI(grupo=u'sistema', nombre=u'respuesta').valor
            return pregunta, respuesta
        else:
            pregunta = atributoI(grupo=u'sistema', nombre=u'pregunta2').valor
            respuesta = atributoI(grupo=u'sistema', nombre=u'respuesta2').valor
        return pregunta, respuesta
    except:
        return None, None


def elimina(rol):
    session().delete(rol)
    session().commit()


def eliminaCuenta(cuentaId):
    propio = rolI(tipo=u'propio')

    atributo = [x for x in propio.atributos if x.id==cuentaId][0]

    session().delete(atributo)
    session().commit()

    # f=g
    #! Necesita refactorizacion

    # registro = session().query(Rol).filter(Rol.tipo==u'propio').one()

    # registro.dato2 = registro.dato2.replace("%s; " % cuenta, "").replace("; %s" % cuenta, "").replace("%s" % cuenta, "")
    # session().update(registro)
    # session().commit()


def guardarContrasena(pwd, modo=None):
    try:
        if not modo:
            atributo = atributoI(grupo=u'sistema', nombre=u'contraseña')
        else:
            atributo = atributoI(grupo==u'sistema', nombre=u'contraseña2')
        atributo.valor = pwd
    except:
        if not modo:
            atributo = atributoI(grupo=u'sistema', nombre=u'contraseña', valor=u"%s" % pwd, referencia=u'1')
        else:
            atributo = atributoI(grupo=u'sistema', nombre=u'contraseña2', valor=u"%s" % pwd, referencia=u'1')
    session().commit()


def guardarRecuperacion(pregunta, respuesta, modo=None):    # print "man.guardarRecuperacion()"
    if not modo:
        atributo = atributoI(grupo=u'sistema', nombre=u'pregunta', valor=u"%s" % pregunta, referencia=u'1')
        atributo = atributoI(grupo=u'sistema', nombre=u'respuesta', valor=u"%s" % respuesta, referencia=u'1')
    else:
        atributo = atributoI(grupo=u'sistema', nombre=u'pregunta2', valor=u"%s" %pregunta2, referencia=u'1')
        atributo = AtributoI(grupo=u'sistema', nombre=u'respuesta2', valor=u"%s" % respuesta2, referencia=u'1')
    session().add(atributo)
    session().commit()


def incrementRunCount():
    try:
        atributo = atributoI(grupo=u'system', nombre=u'runCount')
        atributo.valor = u"%s" % (int(atributo.valor) + 1)
        session().commit()
        return True
    except:
        return False


def ponCuentas(cuentas):
    f=g
    #! Necesita refactorizacion

    cuentasString = u""
    for cuenta in cuentas:
        cuentasString += "%s; " % cuenta
    cuentasString = cuentasString.rstrip("; ")
    registro = session().query(Rol).filter(Rol.tipo==u'propio').one()
    registro.dato2 = cuentasString
    session().update(registro)
    session().commit()


def operacionI(**datos):
    #! No se ha implementado el caso de que se reciba una instancia como parámetro
    if 'proceso' in datos.keys():
        proceso = datos.pop('proceso')
        procesoId = proceso.id
        operacion = session().query(Operacion).filter_by(**datos).filter(Operacion.procesos.any(id=procesoId)).first()
    elif 'proceso_id' in datos.keys():
        procesoId = datos.pop('proceso_id')
        operacion = session().query(Operacion).filter_by(**datos).filter(Operacion.procesos.any(id=procesoId)).first()

    else:
        """ Primero se prueba con todos los parámetros
            por si se trata de una consulta, también funciona si se recibe sólo el id """
        proceso = None
        procesoId = None
        operacion = session().query(Operacion).filter_by(**datos).first()

    if not operacion:
        """ Si no es consulta, es modificación o alta """
        """ Si se recibe el id y no se trata de una consulta (algún parámetro no coincide con el contenido en la base de datos), se trata de una modificación"""
        if 'id' in datos.keys():
            operacion = session().query(Operacion).filter(Operacion.id==datos.pop('id')).first()
        if not operacion:
            """Se insiste si se trata de modificación, búsqueda por unique constraint"""
            if procesoId:
                operacion = session().query(Operacion).filter(Operacion.tipo==datos['tipo']).filter(Operacion.procesos.any(id=procesoId)).first()
        if not operacion:
            """ Si no es modificación, es alta """
            operacion = Operacion(**datos)
        else:
            operacion.setData(**datos)

        if not proceso:
            proceso = session().query(Proceso).filter(Proceso.id==procesoId).one()

        proceso.operaciones.append(operacion)

        session().add(operacion)

        session().commit()

    return operacion



def rolI(**datos):

    entidad = None
    entidadDict = {}
    if 'personalidad' in datos.keys(): entidadDict['personalidad'] = datos['personalidad']
    if 'nombre' in datos.keys(): entidadDict['nombre'] = datos['nombre']
    if 'nombre2' in datos.keys(): entidadDict['nombre2'] = datos['nombre2']
    if 'rfc' in datos.keys():   entidadDict['rfc'] = datos['rfc']
    if 'alias' in datos.keys(): entidadDict['alias'] = datos['alias']

    if entidadDict:
        if 'entidad_id' in datos.keys():
            entidad = session().query(Entidad).filter(Entidad.id==datos['entidad_id']).one()
        else:
            entidad = session().query(Entidad).filter_by(**entidadDict).first()
            if not entidad:
                entidad = Entidad(**entidadDict)
        entidad.setData(**entidadDict)
        session().add(entidad)
        session().flush()

    rolDict = {}
    if 'id' in datos.keys(): rolDict['id'] = datos['id']
    if entidad:              rolDict['entidad_id'] = entidad.id

    if 'tipo_id' in datos.keys():
        rolDict['tipo_id'] = datos['tipo_id']
    elif 'tipo' in datos.keys():
        rolDict['tipo_id'] = atributoI(grupo=u'tipoRol', nombre=datos.pop('tipo')).id

    if 'code' in datos.keys():  rolDict['code'] = datos['code']
    if 'funcion' in datos.keys():
        print p, "WARNING: Someone is using the funcion field of rol instance"
        rolDict['funcion'] = datos['funcion']
    if 'comentarios' in datos.keys(): rolDict['comentarios'] = datos['comentarios']
    if 'dato1' in datos.keys(): rolDict['dato1'] = datos['dato1']
    if 'dato2' in datos.keys(): rolDict['dato2'] = datos['dato2']

    if 'id' in datos.keys():
        rol = session().query(Rol).filter(Rol.id==datos['id']).one()
    else:
        rol = session().query(Rol).filter_by(**rolDict).first()
        if not rol:
            rol = Rol(**rolDict)
            entidad.roles.append(rol)

    rol.setData(**rolDict)
    session().add(rol)
    session().flush()

    ## FUNCIONES
    if 'funciones' in datos.keys():
        for item in datos['funciones']:
            funcion = atributoRolI(rol_id=rol.id, nombre=u'función', valor=item[1])
            rol.atributos.append(funcion)

    ## LUGAR
    if not 'lugar_id' in datos.keys():
        if 'lugar' in datos.keys():
            try:
                lugar = session().query(Atributo).filter(Atributo.grupo==u'lugar').filter(Atributo.nombre==datos['lugar']).one()
            except:
                lugar = Atributo(grupo=u'lugar', nombre=datos['lugar'])
                session().add(lugar)
            datos['lugar_id'] = lugar.id

    ## DIRECCION
    direccionDict = {}
    if 'areanominal' in datos.keys(): direccionDict['areanominal'] = datos['areanominal']
    if 'areapostal' in datos.keys(): direccionDict['areapostal'] = datos['areapostal']
    if 'areatelefonia' in datos.keys(): direccionDict['areatelefonia'] = datos['areatelefonia']
    if 'calle' in datos.keys(): direccionDict['calle'] = datos['calle']
    if 'lugar_id' in datos.keys(): direccionDict['lugar_id'] = datos['lugar_id']

    if direccionDict:
        if 'direccion_id' in datos.keys():
            try:
                direccion = [x for x in rol.direcciones if x.id==datos['direccion_id']][0]
            except:
                direccion = session().query(Direccion).filter(Direccion.id==datos['direccion_id']).one()
            direccion.setData(**direccionDict)
        else:
            #! Falta validar mas de una direccion
            direccion = Direccion(**direccionDict)
            rol.direcciones = [direccion]
        session().add(direccion)

    ## CONTACTO
    if 'contactos' in datos.keys():
        for item in datos['contactos']:
            contacto = atributoRolI(rol_id=rol.id, nombre=item[0], valor=item[1])
            rol.atributos.append(contacto)

    # contactoDict = {}
    # if 'telefonoFijo' in datos.keys():
        # contactoDict['rol_id'] = rol.id
        # contactoDict['nombre'] = u'tel fijo'
        # contactoDict['valor'] = datos['telefonoFijo']

    # if contactoDict:
        # if 'contacto_id' in datos.keys():
            # try:
                # contacto = [x for x in rol.atributos if x.id==datos['contacto_id']][0]
            # except:
                # contacto = session().query(AtributoRol).filter(AtributoRol.id==datos['contacto_id']).one()
            # contacto.setData(**contactoDict)
        # else:
            ##! Falta validar mas de un contacto
            # contacto = AtributoRol(**contactoDict)
            # rol.atributos.append(contacto)
        # session().add(contacto)
        # session().flush()

    session().commit()

    # rol = rol(id=rol.id)
    return rol


def rolesI(**filtros):
    #! Parece que tipo solo busca por cliente
    if 'tipo' in filtros.keys():
        filtros['tipo_id'] = atributoI(grupo=u'tipoRol', nombre=filtros.pop('tipo')).id

    if 'rfc' in filtros.keys():
        roles = session().query(Rol).join(Entidad).filter(Entidad.rfc==filtros['rfc']).all()

    elif filtros.has_key('nombre'):
        mask = filtros.pop('nombre')
        roles = session().query(Rol).filter_by(**filtros).join(Entidad).filter(sqlalchemy.or_(sql.func.lower(Entidad.nombre).like(u"%%%s%%" % mask.lower()), sql.func.lower(Entidad.nombre2).like(u"%%%s%%" % mask.lower()))).all()

    elif filtros.has_key('nombre2'):
        roles = session().query(Rol).join(Entidad).filter(Entidad.nombre2==filtros['nombre2']).all()

    elif filtros.has_key('order'):
        if filtros['order'] == 'nombre':
            roles = session().query(Rol).filter(Rol.tipo_id==filtros['tipo_id']).join(Entidad).filter(Entidad.nombre!=u'').order_by(Entidad.nombre).order_by(Entidad.nombre2).all()
        if filtros['order'] == 'nombre2':
            roles = session().query(Rol).filter(Rol.tipo_id==filtros['tipo_id']).join(Entidad).filter(Entidad.nombre2!=u'').order_by(Entidad.nombre2).order_by(Entidad.nombre).all()

    elif 'funcion' in filtros.keys():
        roles = session().query(Rol).filter(Rol.tipo_id==filtros['tipo_id']).join(AtributoRol).filter(AtributoRol.nombre==u'función').filter(sql.func.lower(AtributoRol.valor)==filtros['funcion']).all()

    else:
        roles = session().query(Rol).filter(Rol.tipo_id==filtros['tipo_id']).all()

    return roles


def rolExists(**filtros):
    m = "man.rolExists()"

    try:
        if 'rfc' in filtros.keys():
            rfc = filtros.pop('rfc')
            if filtros:
                rol = session().query(Rol).filter_by(**filtros).join(Entidad).filter(Entidad.rfc==rfc).one()
            else:
                rol = session().query(Rol).join(Entidad).filter(Entidad.rfc==rfc).one()
        else:
            rol = session().query(Rol).filter_by(**filtros).one()
    except:
        return False


def runCount(increment=False):
    atribute = atributoI(grupo=u'system', nombre=u'runCount')
    if increment:
        atribute.valor = unicode(int(atribute.valor)+1)
        session().commit()
    else:
        return int(atribute.valor)


def testPassword(pwd, modo=None):   # print "man.testPassword()"
    if not modo or modo==u'Normal' or modo==u'Remoto':
        result = atributoI(grupo=u'sistema', nombre=u'contraseña')
        if result.valor == pwd:
            return int(result.referencia)
        else:
            return False
    elif modo==u'herramientas':
        result = atributoI(grupo=u'sistema', nombre=u'contraseña2')
        if result.valor == pwd:
            return int(result.referencia)
        else:
            return False


def getRecovery(mode=None):
    try:
        if not mode:
            question = session().query(Attribute).filter(Attribute.group==u'system').filter(Attribute.name==u'question').one().value
            answer = session().query(Attribute).filter(Attribute.group==u'system').filter(Attribute.name==u'answer').one().value
            return question, answer
        else:
            question = session().query(Atributo).filter(Atributo.group==u'system').filter(Attribute.name==u'question2').one().value
            answer = session().query(Atributo).filter(Attribute.group==u'system').filter(Attribute.name==u'answer2').one().value
        return question, answer
    except:
        return None, None




# def tiposDocumento(**filtros):
    # m = "man.tiposDocumento()"
    # if 'referencia' in filtros.keys():
        # registros = man.session().query(Atributo).filter(Atributo.grupo==u'tipoDocumento').filter(Atributo.referencia.like(u'%%s%' % filtros['referencia'])).all()
    # print (), m, registros
    # return registros






sessionX = None
engine = None

def createSession(data=None):
    m = "man.createSession()"

    global sessionX, engine

    dialect = config.pull('properties', 'dialect')
    if not dialect:
        dialect = 'sqlite'

    if len(data) == 2 or not data[2]:
        data.append(config.pull('properties', 'server'))

    try:
        engine = sqlalchemy.create_engine("%s://%s:%s@%s/bt" % (dialect, data[0], data[1], data[2]), echo=False)
        engine.connect()

    except sqlalchemy.exc.OperationalError, exc:
        if 'base' in str(exc) and str('bt') in str(exc):
            return '42504'      # Database does not exist
        elif 'password' in str(exc):
            if str(data[0]) in str(exc):
                return '20250'  # User name / password combination unknown
            else:
                return '20200'  # No password supplied
        elif 'running' in str(exc) and data[2] in str(exc):
            return '20400'      # Unknown host
        elif 'translate host name' in str(exc):
            return '20400'
        else:
            print 987, str(exc)
            raise
    except:
        config.push('properties', 'error', sys.exc_info())
        raise

        return '?????'

    config.push('properties', 'server', data[2])

    Session = orm.sessionmaker()
    Session.configure(bind=engine)
    sessionX = Session()
    backend.metadata.bind = engine
    return '00000'



def session():
    global sessionX
    return sessionX



def inicializa():
    # result = createSession(config.pull('properties', 'database'))
    # if not result == '00000':
        # return result
    # else:
        backend.metadata.create_all(engine)
        version = atributoI(code=1103, grupo=u'sistema', nombre=u'versionBasedatos').valor

        if not version:
            print "Inicializando Base de datos"
            """
            Se busca que algunos datos tengan una id fija para compatibilidad entre diferentes instancias del sistema

            1100-1199  Sistema
            1200-1399  Procesos, documentos, cuentas, pagos
            1400-1599  Entidades
            1600-1799  Productos
            1800-1999  Pedidos
            2000-2999  Lugares
            """

            registros = [
                {'code':1105, 'grupo':u'sistema', 'nombre':u'ruta', 'valor':u'%s' % os.getcwd()},
                {'code':1107, 'grupo':u'sistema', 'nombre':u'rutaDocumentos', 'valor':u'documentos'},
                {'code':1109, 'grupo':u'sistema', 'nombre':u'contraseña', 'valor':u'firstRun', 'referencia':u'1'},
                {'code':1111, 'grupo':u'sistema', 'nombre':u'contraseña2', 'valor':u'1'},
                {'code':1113, 'grupo':u'sistema', 'nombre':u'contrasenaHerramientas'},
                {'code':1115, 'grupo':u'sistema', 'nombre':u'contrasenaMantenimiento'},
                {'code':1117, 'grupo':u'sistema', 'nombre':u'proteccionF10'},
                {'code':1121, 'grupo':u'system', 'nombre':u'runCount', 'valor':u'0'},
                {'code':1125, 'grupo':u'system', 'nombre':u'useUsername', 'valor':u'1'},
                {'code':1145, 'grupo':u'sistema', 'nombre':u'mostrarTips', 'valor':u'1'},
                {'code':1147, 'grupo':u'sistema', 'nombre':u'tipDefault', 'valor':u'0'},
                {'code':1151, 'grupo':u'sistema', 'nombre':u'impuestoGeneral', 'valor':u'16.00'},

                {'code':1191, 'grupo':u'tipoContacto', 'nombre':u'personal'},
                {'code':1193, 'grupo':u'tipoContacto', 'nombre':u'trabajo'},

                {'code':1205, 'grupo':u'procesos', 'nombre':u'recalcularPreciosAlComprar', 'valor':u'0'},

                {'code':1231, 'grupo':u'statusProcesos', 'nombre':u'abierto'},
                {'code':1233, 'grupo':u'statusProcesos', 'nombre':u'cerrado'},
                {'code':1235, 'grupo':u'statusProcesos', 'nombre':u'cancelado'},

                {'code':1251, 'grupo':u'tipoDocumento', 'nombre':u'pedido', 'referencia':u'pedido'},
                {'code':1253, 'grupo':u'tipoDocumento', 'nombre':u'remisión', 'referencia':u'compra, venta, inventarios, caja'},
                {'code':1255, 'grupo':u'tipoDocumento', 'nombre':u'factura', 'referencia':u'compra, venta, inventarios, caja'},
                {'code':1257, 'grupo':u'tipoDocumento', 'nombre':u'nota de crédito', 'referencia':u'caja'},
                {'code':1259, 'grupo':u'tipoDocumento', 'nombre':u'pagaré', 'referencia':u'cobro, pago, caja'},
                {'code':1261, 'grupo':u'tipoDocumento', 'nombre':u'cheque', 'referencia':u'cobro, pago, caja'},
                {'code':1263, 'grupo':u'tipoDocumento', 'nombre':u'efectivo', 'referencia':u'cobro, pago, caja'},
                {'code':1265, 'grupo':u'tipoDocumento', 'nombre':u'servicio'},

                # {'code':1267, 'grupo':u'tipoDocumentoCompra', 'nombre':u'default', 'valor': }
                # {'code':1269, 'grupo':u'tipoDocumentoVenta', 'nombre':u'default', 'valor': }

                {'code':1271, 'grupo':u'statusDocumento', 'nombre':u'Pendiente'},
                {'code':1273, 'grupo':u'statusDocumento', 'nombre':u'Procesada'},

                {'code':1281, 'grupo':u'folioDocumento', 'nombre':u'compra', 'valor':u'0'},
                {'code':1283, 'grupo':u'folioDocumento', 'nombre':u'ventaFiscal', 'valor':u'0'},
                {'code':1285, 'grupo':u'folioDocumento', 'nombre':u'ventaControl', 'valor':u'0'},
                {'code':1287, 'grupo':u'folioDocumento', 'nombre':u'pedido', 'valor':u'0'},
                {'code':1289, 'grupo':u'folioDocumento', 'nombre':u'servicio', 'valor':u'0'},
                {'code':1291, 'grupo':u'folioDocumento', 'nombre':u'presupuesto', 'valor':u'0'},
                {'code':1293, 'grupo':u'folioDocumento', 'nombre':u'pagaré', 'valor':u'0'},

                {'code':1305, 'grupo':u'cuentas', 'nombre':u'caja', 'referencia':u'1001'},
                {'code':1307, 'grupo':u'cuentas', 'nombre':u'inventarios', 'referencia':u'1002'},
                {'code':1309, 'grupo':u'cuentas', 'nombre':u'pagos', 'referencia':u'1003'},
                {'code':1311, 'grupo':u'cuentas', 'nombre':u'cobros', 'referencia':u'1004'},
                {'code':1313, 'grupo':u'cuentas', 'nombre':u'pasivos', 'referencia':u'1005'},

                {'code':1321, 'grupo':u'formaPago', 'nombre':u'efectivo', 'referencia':u'1'},
                {'code':1323, 'grupo':u'formaPago', 'nombre':u'cheque', 'referencia':u'2'},
                {'code':1325, 'grupo':u'formaPago', 'nombre':u'crédito', 'referencia':u'3'},

                {'code':1331, 'grupo':u'condicionesPago', 'nombre':u"Anticipado", 'valor':u'0'},
                {'code':1333, 'grupo':u'condicionesPago', 'nombre':u"Al recibir", 'valor':u'1'},
                {'code':1335, 'grupo':u'condicionesPago', 'nombre':u"30 días", 'valor':u'30'},
                {'code':1337, 'grupo':u'condicionesPago', 'nombre':u'15 días', 'valor':u'15'},
                {'code':1339, 'grupo':u'condicionesPago', 'nombre':u"10 días", 'valor':u'10'},

                {'code':1351, 'grupo':u'venta', 'nombre':u'capturaPagoObligatoria', 'valor':u'0'},
                {'code':1353, 'grupo':u'venta', 'nombre':u'seImprimeComprobante', 'valor':u'0'},
                {'code':1355, 'grupo':u'venta', 'nombre':u'focusEnSeleccionDeProducto', 'valor':u'0'},

                # {'code':2000, 'grupo':u'lugar', 'nombre':u''},
                {'code':2009, 'grupo':u'lugar', 'nombre':u'Acapulco, Gro.'},
                {'code':2017, 'grupo':u'lugar', 'nombre':u'Aguascalientes, Ags.'},
                {'code':2025, 'grupo':u'lugar', 'nombre':u'Campeche, Camp.'},
                {'code':2033, 'grupo':u'lugar', 'nombre':u'Cd. Juarez, Chih.'},
                {'code':2041, 'grupo':u'lugar', 'nombre':u'Cd. Obregón, Son.'},
                {'code':2049, 'grupo':u'lugar', 'nombre':u'Cd. Victoria, Tamps.'},
                {'code':2057, 'grupo':u'lugar', 'nombre':u'Chetumal, QRoo.'},
                {'code':2065, 'grupo':u'lugar', 'nombre':u'Chihuahua, Chih.'},
                {'code':2073, 'grupo':u'lugar', 'nombre':u'Chilpancingo, Gro.'},
                {'code':2081, 'grupo':u'lugar', 'nombre':u'Colima, Col.'},
                {'code':2089, 'grupo':u'lugar', 'nombre':u'Culiacán, Sin.'},
                {'code':2097, 'grupo':u'lugar', 'nombre':u'Cuernavaca, Mor.'},
                {'code':2105, 'grupo':u'lugar', 'nombre':u'Durango, Dgo.'},
                {'code':2113, 'grupo':u'lugar', 'nombre':u'Guadalajara, Jal.'},
                {'code':2121, 'grupo':u'lugar', 'nombre':u'Guanajuato, Gto.'},
                {'code':2129, 'grupo':u'lugar', 'nombre':u'Guasave, Sin.'},
                {'code':2137, 'grupo':u'lugar', 'nombre':u'Hermosillo, Son.'},
                {'code':2145, 'grupo':u'lugar', 'nombre':u'Jalapa, Ver.'},
                {'code':2153, 'grupo':u'lugar', 'nombre':u'La Paz, B.C.S.'},
                {'code':2161, 'grupo':u'lugar', 'nombre':u'Los Mochis, Sin.', 'valor':u'default'},
                {'code':2169, 'grupo':u'lugar', 'nombre':u'Mazatlán, Sin.'},
                {'code':2177, 'grupo':u'lugar', 'nombre':u'Mérida, Yuc.'},
                {'code':2185, 'grupo':u'lugar', 'nombre':u'Mexicali, B.C.'},
                {'code':2193, 'grupo':u'lugar', 'nombre':u'México, D.F.'},
                {'code':2201, 'grupo':u'lugar', 'nombre':u'Monterrey, N.L.'},
                {'code':2209, 'grupo':u'lugar', 'nombre':u'Morelia, Mich.'},
                {'code':2217, 'grupo':u'lugar', 'nombre':u'Navojoa, Son.'},
                {'code':2225, 'grupo':u'lugar', 'nombre':u'Nogales, Son.'},
                {'code':2233, 'grupo':u'lugar', 'nombre':u'Oaxaca, Oax.'},
                {'code':2241, 'grupo':u'lugar', 'nombre':u'Pachuca, Hgo.'},
                {'code':2249, 'grupo':u'lugar', 'nombre':u'Puebla, Pue.'},
                {'code':2257, 'grupo':u'lugar', 'nombre':u'Queretaro, Qro.'},
                {'code':2265, 'grupo':u'lugar', 'nombre':u'Saltillo, Coah.'},
                {'code':2273, 'grupo':u'lugar', 'nombre':u'San Luis Potosí, S.L.P.'},
                {'code':2281, 'grupo':u'lugar', 'nombre':u'Tepic, Nay.'},
                {'code':2289, 'grupo':u'lugar', 'nombre':u'Tijuana, B.C.'},
                {'code':2297, 'grupo':u'lugar', 'nombre':u'Tlaxcala, Tlax.'},
                {'code':2305, 'grupo':u'lugar', 'nombre':u'Toluca, Edo.Mex.'},
                {'code':2313, 'grupo':u'lugar', 'nombre':u'Tuxtla Gutierrez, Chis.'},
                {'code':2321, 'grupo':u'lugar', 'nombre':u'Villahermosa, Tab.'},
                {'code':2329, 'grupo':u'lugar', 'nombre':u'Veracruz, Ver.'},
                {'code':2337, 'grupo':u'lugar', 'nombre':u'Zacatecas, Zac.'},

                {'code':1, 'grupo':u'tipoEquipo', 'nombre':u'Sedán'},
                {'code':2, 'grupo':u'tipoEquipo', 'nombre':u'Familiar'},
                {'code':3, 'grupo':u'tipoEquipo', 'nombre':u'Monovolumen'},
                {'code':4, 'grupo':u'tipoEquipo', 'nombre':u'Furgoneta'},
                {'code':5, 'grupo':u'tipoEquipo', 'nombre':u'Utilitario'},
                {'code':6, 'grupo':u'tipoEquipo', 'nombre':u'Pickup'},
                {'code':7, 'grupo':u'tipoEquipo', 'nombre':u'Reparto'},

                {'code':3, 'grupo':u'marcaEquipo', 'nombre':u'BMW'},
                {'code':7, 'grupo':u'marcaEquipo', 'nombre':u'Cadillac'},
                {'code':11, 'grupo':u'marcaEquipo', 'nombre':u'Chevrolet'},
                {'code':15, 'grupo':u'marcaEquipo', 'nombre':u'Chrysler'},
                {'code':19, 'grupo':u'marcaEquipo', 'nombre':u'Ford'},
                {'code':23, 'grupo':u'marcaEquipo', 'nombre':u'Honda'},
                {'code':27, 'grupo':u'marcaEquipo', 'nombre':u'Hummer'},
                {'code':31, 'grupo':u'marcaEquipo', 'nombre':u'Hyundai'},
                {'code':35, 'grupo':u'marcaEquipo', 'nombre':u'Jeep'},
                {'code':39, 'grupo':u'marcaEquipo', 'nombre':u'Mazda'},
                {'code':43, 'grupo':u'marcaEquipo', 'nombre':u'Mercedes'},
                {'code':47, 'grupo':u'marcaEquipo', 'nombre':u'Mitsubishi'},
                {'code':51, 'grupo':u'marcaEquipo', 'nombre':u'Nissan'},
                {'code':55, 'grupo':u'marcaEquipo', 'nombre':u'Pontiac'},
                {'code':59, 'grupo':u'marcaEquipo', 'nombre':u'Renault'},
                {'code':63, 'grupo':u'marcaEquipo', 'nombre':u'Seat'},
                {'code':67, 'grupo':u'marcaEquipo', 'nombre':u'Toyota'},
                {'code':71, 'grupo':u'marcaEquipo', 'nombre':u'Volkswagen'},

                {'code':0, 'grupo':u'clasificacionProducto', 'nombre':u''}
                ]

            # id=1261, grupo=u'default', nombre=u'tipoDocumentoCompra', valor=
            # id=1263, grupo=u'default', nombre=u'tipoDocumentoVenta', valor=
            # id=2001, grupo=u'default', nombre=u'lugar', valor=

            for registro in registros:
                atributoI(**registro)

            marca = atributoI(grupo=u'marcaEquipo', nombre=u'Ford')

            registros = [
                {'code':3, 'grupo':u'lineaEquipo', 'nombre':u'Ikon', 'referencia':u'%s' % marca.id},
                {'code':7, 'grupo':u'lineaEquipo', 'nombre':u'Focus', 'referencia':u'%s' % marca.id},
                {'code':11, 'grupo':u'lineaEquipo', 'nombre':u'Mondeo', 'referencia':u'%s' % marca.id},
                {'code':15, 'grupo':u'lineaEquipo', 'nombre':u'Mustang', 'referencia':u'%s' % marca.id},
                {'code':19, 'grupo':u'lineaEquipo', 'nombre':u'F', 'referencia':u'%s' % marca.id},
                {'code':23, 'grupo':u'lineaEquipo', 'nombre':u'Navigator', 'referencia':u'%s' % marca.id}
                ]

            for registro in registros:
                atributoI(**registro)

            tipoDocumento = atributoI(grupo=u'tipoDocumento', nombre=u'factura')
            atributoI(code=1267, grupo=u'tipoDocumentoCompra', nombre=u'default', valor=unicode(tipoDocumento.id))

            tipoDocumento = atributoI(grupo=u'tipoDocumento', nombre=u'remisión')
            atributoI(code=1269, grupo=u'tipoDocumentoVenta', nombre=u'default', valor=unicode(tipoDocumento.id))

            session().flush()

            atributoI(grupo=u'sistema', nombre=u'versionBasedatos', valor=u"52")
            version = 52

            session().commit()


        return '00000'



# print (0), "man                 end"




"""
# ###########################################################
Versionado de Base de datos

Al crearse la bd no se encuentra el registro de version porque no se ha
inicializado, se inicializa ese registro y todos los necesarios, este
registro contendrá el número de la versión mas reciente, así no se aplican
los cambios de las versiones anteriores, ya que esos cambios ya se incluyeron
en la creación de las tablas e inicialización de datos.
El número de versión no se reiniciará nunca.

Manejo de Documentos

    Manejo de partidas
        La partida maneja la id de acepcion en oposicion a la id de producto o
        al manejo de ambos.

        La partida maneja la id de producto en oposicion a la id de la acepcion
        o al manejo de ambos.


# ###########################################################
"""


"""
Lógica de negocios

Cuando se da de baja un proveedor o un cliente, en la estructura de datos se
está eliminando un rol, hay que ver si se da de baja la entidad también o se
deja guardada para próximos movimientos, como alta de otros roles o del mismo

Al dar de alta un proveedor o un cliente, en la estructura de datos
se esta agregando un rol, hay que validar si se está refiriendo a una entidad
nueva o una que ya existe.


Cuentas de activo.
    Caja
    Inventarios
    Por cobrar
    ...

Cuentas de pasivo.
    Por pagar


Operación
    Proceso que traslada un producto de una entidad a otra.


Transacción
    Conjunto de operaciones que se desprenden de una operación base.
    Ej: Compra
            Pedido
            Factura
            Pago

        Se registra:
            Pedido:
                Nada

            Factura:
                Un movimiento de abono en la cuenta Inventarios
    ['inventarios', '15DIC08 15:31', [id, 'GSEB', '10DIC08', 1321.87, 'activo'], 1217.76, activo]

                Un movimiento de cargo en la cuenta Por pagar
    ['por pagar', '15DIC08 23:59', [id, 'GSEB', '10DIC08', 1321.87, 'activo'], 1321.87, activo]

            Pago:
                Un movimiento de abono a la cuenta Por pagar
    ['por pagar', '15DIC08 23:59', [id, 'GSEB', '10DIC08', 1321.87, 'activo'], 1321.87, activo]

                Un movimiento de cargo a la cuenta Caja
    ['caja', '15DIC08 23:59', [id, 'GSEB', '10DIC08', 1321.87, 'activo'], 1321.87, activo]

    Ej: Venta
            Factura
            Pago

        Se registra:
            Factura:
                Un movimiento de cargo en la cuenta Inventarios
    ['inventarios', '15DIC08 15:31', [id, 'yomero', '10DIC08', 132.87, 'activo'], 132.87, activo]

                Un movimiento de abono en la cuenta Por cobrar
    ['por cobrar', '15DIC08 23:59', [id, 'GSEB', '10DIC08', 1321.87, 'activo'], 1321.87, activo]

            Pago:
                Un movimiento de abono a la cuenta Por pagar
    ['por pagar', '15DIC08 23:59', [id, 'GSEB', '10DIC08', 1321.87, 'activo'], 1321.87, activo]

                Un movimiento de cargo a la cuenta Caja
    ['caja', '15DIC08 23:59', [id, 'GSEB', '10DIC08', 1321.87, 'activo'], 1321.87, activo]

Tabla de cuentas
    id
    tipo        ['caja', 'bancos', 'inventarios', 'creditos']
    documento
    status

Saldos
    Se maneja un sólo saldo de referencia como inicio de ciclo, los saldos en
    cualquier momento posterior se determinan aplicando todos los movimientos
    pertinentes
"""


if __name__ == "__main__":
    createSession('postgresql://postgres:postgres@criptidosdigitales.com/bt')

    registros = session().query(Atributo).all()

    print registros




"""
    Procesos en progreso ...

    Implementación del uso del método 'atributo' en el controlador (como todavia no está implementado el controlador, sería en el manejador (en este caso man) (que debería ser modelo)), de manera que cuando se quiera crear una instancia de la clase Atributo se obtenga con este método en lugar de instanciar directamente, además, este método deberá proporcionar una instancia ya existente si los parámetros lo permiten. La idea es unificar los métodos agregarAtributo, dameAtributo, actualizarAtributo y eliminar la instanciación directa. En el caso de la modificación, se asumirá que se requiere si se llamó el método con una instancia como parámetro o el campo 'id' existe en los parámetros.

    Se aprovecha la refactorización del manejo de atributo para refactorizar el manejo del atributo lugar. Las clases que usen el atributo lugar podrán recibir como parámetro el lugar en una de las dos siguientes maneras, la clase usa el campo lugar_id para almacenar el lugar en forma del id de atributo del lugar, esta forma de parámetro sería la primera y la mas directa, la segunda sería en forma del valor de atributo que es el nombre del lugar y se usaría principalmente cuando se trate de un lugar nuevo que se tiene que dar de alta, y secundariamente (no recomendado) cuando no se cuente con el id del registro de atributo, esto obliga a una busqueda previa del atributo en la base de datos. Debido a que el modelo sólo regresa instancias y los lugares no cuentan con una clase propia, se regresan instancias de la clase Atributo, es por esto que se recomienda usar llamadas a los métodos para atributo en lugar de los métodos específicos para lugares.
"""
